package org.eclipse.equinox.spring.osgi.deployer;
/**
 * This file is part of org.springframework.equinox.deployer. 
 * Copyright (C) olivier.evalet@genebio.com and genebio team
 * 
 * org.springframework.equinox.deployer is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 * 
 * org.springframework.equinox.deployer is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * org.springframework.equinox.deployer. If not, see <http://www.gnu.org/licenses/>.
 *
 * Special thanks for Bernd Kolb the first author of this file   
 */

import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Properties;

import javax.servlet.Filter;
import javax.servlet.Servlet;

import org.apache.commons.logging.Log;
import org.eclipse.equinox.http.helper.BundleEntryHttpContext;
import org.eclipse.equinox.http.helper.ContextListenerServletAdaptor;
import org.eclipse.equinox.http.helper.ContextPathServletAdaptor;
import org.eclipse.equinox.http.helper.FilterServletAdaptor;
import org.eclipse.equinox.http.helper.ResourceServlet;
import org.eclipse.equinox.jsp.jasper.JspServlet;
import org.eclipse.equinox.spring.osgi.AppContextAwareHttpServiceTracker;
import org.eclipse.equinox.spring.osgi.OsgiBundleWebContext;
import org.eclipse.equinox.spring.osgi.OsgiContextLoaderListener;
import org.eclipse.equinox.spring.osgi.SpringServlet;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.springframework.context.ApplicationContext;
import org.springframework.osgi.service.importer.support.LocalBundleContext;
import org.springframework.osgi.util.OsgiListenerUtils;
import org.springframework.osgi.util.OsgiServiceReferenceUtils;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;

/**
 * His class is a HUGE hack to help understand the spring loaders (MVC, SECURITY, ...)
 * @author evaleto
 */

public class OsgiSpringWebappDeployer extends AppContextAwareHttpServiceTracker {

	
	private static final String KEY_MVC_URI 		= "mvc-uri";
	private static final String KEY_MVC_CONF 		= "mvc-config";
	private static final String KEY_WEBCONTEXT_PATH	= "webcontext-path";
	private static final String KEY_WEBCONTEXT		= "webcontext";
	private static final String KEY_SECURITY		= "security";
	private static final String KEY_SECURITY_URL 	= "security-url";
	private static final String KEY_SECURITY_BEAN 	= "security-bean";
	private static final String NULL_PATH	 		= "/null-context-listener";
	
	private String mvcuri;
	private String webapp;
	private String applicationcontext;
	private String security;
	private String webappname;
	private Log	log=org.apache.commons.logging.LogFactory.getLog(OsgiSpringWebappDeployer.class);
	
	private String strutsconf;
	private String strutsname;
	private String strutsext;
	
	public OsgiSpringWebappDeployer(BundleContext context) {
		super(context);
	}


	/**
	 * default is /web
	 * @param path
	 */

		
	protected void addServiceInternal(ApplicationContext appContext,
			HttpService httpService) throws Exception {
		
		
		mvcuri=getConfig(KEY_MVC_URI, null);
		webapp=getConfig(KEY_WEBCONTEXT_PATH, "/web");
		applicationcontext=getConfig(KEY_WEBCONTEXT, "/");
		security=getConfig(KEY_SECURITY_URL, "/*");
		applicationcontext=(applicationcontext.equals("/"))?"":applicationcontext;
		
		
		log.info("local bunlde: "+LocalBundleContext.getInvokerBundleContext());
		
		
		HttpContext commonContext = new BundleEntryHttpContext(context.getBundle(), webapp);

		//load spring listener by fake servlet creation 
		Servlet listener = new ContextListenerServletAdaptor(new OsgiContextLoaderListener(appContext,context),new ResourceServlet("/"));
		httpService.registerServlet(applicationcontext+NULL_PATH, listener, null, commonContext);

		// dispatch jsp files
		Servlet jspContextPath=new ContextPathServletAdaptor(new JspServlet(context.getBundle(), webapp), applicationcontext);		
		httpService.registerServlet(applicationcontext+"/*.jsp", getAcegiFilterProxy(jspContextPath), null, commonContext);
		

		// dispatch resources files
		Servlet resourcesContextPath = new ContextPathServletAdaptor(new ResourceServlet("/"), applicationcontext);
		httpService.registerServlet(applicationcontext, getAcegiFilterProxy(resourcesContextPath), null, commonContext);
		
		
		// create the spring mvc dispatcher (root path is defined by commonContext)
		if (mvcuri!=null){
			Dictionary<String,String> dispatchparams = new Hashtable<String,String>();
//			dispatchparams.put("load-on-startup", "2");
			OsgiBundleWebContext.setCurrentContext(context);
			DispatcherServlet dispatch=new DispatcherServlet();
			dispatch.setContextClass(OsgiBundleWebContext.class);
			dispatch.setContextConfigLocation(getConfig(KEY_MVC_CONF,"/META-INF/dispatcher/dispatch-servlet.xml"));
			Servlet dispatchContextPath=new ContextPathServletAdaptor(dispatch, applicationcontext);
			httpService.registerServlet(applicationcontext+mvcuri, getAcegiFilterProxy(dispatchContextPath), dispatchparams, commonContext);
		}
		
		//load custom servlets declared by spring 
		if (getServlets()!=null)
			for (SpringServlet servlet:getServlets()){
				Servlet contextPathServlet = new ContextPathServletAdaptor(servlet, applicationcontext);
				httpService.registerServlet(applicationcontext+servlet.getUri(), 
						getAcegiFilterProxy(contextPathServlet)
								,(Hashtable<String, String>)servlet.getInitConfig(), commonContext);
			}

	}
	public void removedService(ServiceReference reference, Object service) {
		final HttpService httpService = (HttpService) service;
		// unload servlets
		for (SpringServlet servlet:getServlets())
			httpService.unregister(servlet.getUri());
		
		// unload spring mvc
		if (mvcuri!=null)
			httpService.unregister(mvcuri);
		
		// unload .jsp
		httpService.unregister(applicationcontext+"/*.jsp");
		
		//unload spring listener
		httpService.unregister(applicationcontext+NULL_PATH);
		
		super.removedService(reference, service);
	}
	
	public Servlet getAcegiFilterProxy(Servlet adapted){
		// TODO check if security is available as OSGI service
		//		Filter service = (Filter) context.getService(context.getServiceReference("org.springframework.security.util.FilterChainProxy"));
		//		ServiceReference service=OsgiServiceReferenceUtils.getServiceReference(context, "org.springframework.security.util.FilterChainProxy",null);
		
		ServiceReference service=context.getServiceReference("org.springframework.security.util.FilterChainProxy");
		log.info(context.getBundle().getSymbolicName()+" is looking for security service : "+service);
		if (service==null)
			return adapted;
		context.getService(service);
		
		Properties params = new Properties();
		params.put("url-pattern", "/*");
		DelegatingFilterProxy filterproxy=new DelegatingFilterProxy();
		filterproxy.setTargetBeanName("_filterChainProxy");
		log.info("create acegi filter on /*" );

		return new FilterServletAdaptor(filterproxy,params, adapted);
	}	
	
	public Servlet getContextPathSerlvet(Servlet servlet,String contextpath){
		if(contextpath==null || contextpath.equals(""))
			return servlet;
		return new ContextPathServletAdaptor(servlet, contextpath);
	}
}
